package com.toe.order.webapi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.toe.business.service.BusinessInformationService;
import com.toe.commodity.service.CommodityClassesService;
import com.toe.common.exception.NoRollbackForToeServiceException;
import com.toe.common.exception.ToeServiceException;
import com.toe.common.pojo.ali.Alipay;
import com.toe.common.restful.StateEnum;
import com.toe.common.utils.TimeUtil;
import com.toe.order.webapi.repository.IOrderGoodsRedisRepository;
import com.toe.common.utils.AliPayEnum;
import com.toe.common.utils.AliPayUtil;
import com.toe.common.utils.SnowFlakeUtil;
import com.toe.pojo.dto.order.AddOrderClassDTO;
import com.toe.pojo.entity.business.BusinessInformation;
import com.toe.order.webapi.mapper.OrderClassMapper;
import com.toe.order.service.OrderClassService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.toe.pojo.entity.user.UserHaveBuy;
import com.toe.pojo.vo.commodity.CommodityOrderClassVO;
import com.toe.pojo.vo.order.*;
import com.toe.pojo.entity.order.OrderClass;
import com.toe.user.service.UserHaveBuyService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.text.ParseException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 陶涛
 * @since 2022-07-19
 */
@Service
@Transactional(noRollbackFor = NoRollbackForToeServiceException.class)
public class OrderClassServiceImpl extends ServiceImpl<OrderClassMapper, OrderClass> implements OrderClassService {

    @Autowired
    OrderClassMapper orderClassMapper;

    @Autowired
    IOrderGoodsRedisRepository redisRepository;

    @DubboReference
    BusinessInformationService dubboBusinessService;

    @DubboReference
    CommodityClassesService dubboClassService;

    @DubboReference
    UserHaveBuyService dubboUserHaveBuyService;

    /**
     * 添加新订单
     *
     * @param addOrderClassDTO
     */
    public Long addNewOrder(AddOrderClassDTO addOrderClassDTO) {
        // 判断课程是否有购买
        UserHaveBuy one = dubboUserHaveBuyService.getByUserIdClassesId(
                addOrderClassDTO.getUserId(), addOrderClassDTO.getClassId());
        if (one != null) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "该课程已购买,请直接观看");
        }

        CommodityOrderClassVO classById = dubboClassService
                .getOrderClassById(addOrderClassDTO.getClassId());

        if (classById == null) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "服务器忙,请稍后重试");
        }

        OrderClass orderClass = new OrderClass();
        BeanUtils.copyProperties(addOrderClassDTO, orderClass);
        orderClass.setPrice(classById.getPresentPrice());
        System.out.println("price: "+classById.getPresentPrice());
        orderClass.setIsDelete(0);
        orderClass.setState(0);

        SnowFlakeUtil orderNumber = new SnowFlakeUtil(
                0, 0, 1480166465631L);
        orderClass.setOrderNumber(orderNumber.getSnowFlakeNumber());

        LocalDateTime localDateTime = LocalDateTime.now();
        Date date = Date.from(localDateTime
                .atZone(ZoneId.systemDefault())
                .toInstant());
        orderClass.setCreateTime(date);
        orderClass.setUpdateTime(date);
        int rows = orderClassMapper.insert(orderClass);
        if (rows == 0) {
            throw new ToeServiceException(
                    StateEnum.ERR_SERVER_ERROR, "添加订单失败,服务器忙,请稍后重试");
        }
        return orderClass.getId();
    }

    /**
     * 删除订单
     *
     * @param orderId
     */
    public void deleteByOrderId(Long orderId) {
        OrderClass order = orderClassMapper.selectById(orderId);
        if (order == null || order.getIsDelete() == 1) {
            throw new ToeServiceException(StateEnum.ERR_ORDER_EMPTY,
                    "订单不存在");
        }

        int rows = orderClassMapper.deleteById(orderId);
        if (rows == 0) {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "删除失败,服务器忙,请稍后重试");
        }

//        // 更新缓存
//        if (redisRepository.hasDetailsData(orderId)) {
//            redisRepository.deleteValue(orderId);
//        }
    }

    /**
     * 通过订单id查询订单详情信息
     *
     * @param orderId
     * @return
     */
    public OrderClassDetailsVO getOrderDetails(Long orderId) {
        System.out.println("---------------进来了---------------");
        OrderClassDetailsVO orderClassDetails = null;

        // redis缓存
//        if (redisRepository.hasDetailsData(orderId)) {
//            orderGoodsDetails = redisRepository.getOrderDetails(orderId);
//            if (orderGoodsDetails != null) {
//                System.out.println("-----createTime: " + orderGoodsDetails.getCreateTime());
//
//                if (orderGoodsDetails.getState() == 0
//                        && orderGoodsDetails.getIsDelete() == 0) {
//                    String time = TimeUtil.getRemainingPayTime(
//                            orderGoodsDetails.getCreateTime().plusMinutes(15));
//                    if (time == null) {
//                        System.out.println("--------------没有设置时间--------------");
//                        Integer rows = updateIsEnable(orderGoodsDetails.getId());
//                        if (rows == 0) {
//                            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
//                                    "服务器忙,请稍后重试");
//                        }
//
//                        // 修改缓存中的值
//                        orderGoodsDetails.setState(2);
//                        redisRepository.saveDetailsValue(orderGoodsDetails);
//                    } else {
//                        System.out.println("--------------开始设置时间--------------");
//                        orderGoodsDetails.setRemainingPayTime(time);
//                    }
//                }
//                System.out.println("--------------返回缓存中的值---------------");
//                return orderGoodsDetails;
//            }
//        }

        // 开始数据库查询
        OrderClass orderClass = orderClassMapper.selectById(orderId);

        if (orderClass == null || orderClass.getIsDelete() == 1) {
            redisRepository.saveDetailsEmptyValue(orderId);
            throw new ToeServiceException(StateEnum.ERR_ORDER_EMPTY,
                    "订单不存在");
        }

        System.out.println("-----数据库查询的createTime: "
                + orderClass.getCreateTime());
        orderClassDetails = new OrderClassDetailsVO();
        BeanUtils.copyProperties(orderClass, orderClassDetails);
        // 储存时间
        orderClassDetails.setCreateTime(TimeUtil
                .dateToLocalDateTime(orderClass.getCreateTime()));
        System.out.println("-----存入的createTime: "
                + orderClassDetails.getCreateTime());

        System.out.println("==========开始查询商品==========");
        System.out.println("classId: "+orderClass.getClassId());
        CommodityOrderClassVO classById =
                dubboClassService.getOrderClassById(orderClass.getClassId());
        System.out.println("================查询没有异常==============");
        System.out.println("goods -> " + classById);
        orderClassDetails.setClassTitle(classById.getTitle());
        orderClassDetails.setClassType(classById.getTypeName());
        orderClassDetails.setClassCover(classById.getCover());
        orderClassDetails.setBusinessId(classById.getBusinessId());

        orderClassDetails.setPrice(classById.getPresentPrice());
        orderClassDetails.setTolPrice(orderClass.getPrice());

        BusinessInformation business =
                dubboBusinessService.getById(classById.getBusinessId());
        orderClassDetails.setBusinessName(business.getName());

        System.out.println("=====开始设置剩余时间=====");
        if (orderClass.getIsDelete() == 0
                && orderClass.getState() == 0) {
            System.out.println("进来设置");
            String time = TimeUtil.getRemainingPayTime(
                    orderClass.getCreateTime());
            if (time == null) {
                Integer rows = updateIsEnable(orderClass.getId());
                if (rows == 0) {
                    throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                            "服务器忙,请稍后重试");
                }
                orderClassDetails.setState(2);
            } else {
                orderClassDetails.setRemainingPayTime(time);
            }
        }
        System.out.println("设置完毕: " + orderClassDetails.getRemainingPayTime());

//        redisRepository.saveDetailsValue(orderClassDetails);

        System.out.println("---------------返回数据库的值---------------");
        return orderClassDetails;
    }

    /**
     * 查询该用户的所有订单
     *
     * @param userId
     * @return
     */
    public List<OrderClassSimpleVO> listAllOrderByUserId(
            Long userId, int pageNum, int pageSize) {

        System.out.println("进来了pageNum: " + pageNum + "  pageSize: " + pageSize);
        PageHelper.startPage(pageNum, pageSize);

        QueryWrapper<OrderClass> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
                .eq("is_delete", 0);

        System.out.println("开始分页");
        List<OrderClass> order = orderClassMapper.selectList(wrapper);
        System.out.println("---------------------size: " + order.size());

        return getSimpleOrder(order);

    }

    /**
     * 查询该用户所有取消的订单
     *
     * @param userId
     * @return
     */
    public List<OrderClassSimpleVO> listCancelOrderByUserId(
            Long userId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        QueryWrapper<OrderClass> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
                .eq("is_delete", 0)
                .and(wq -> wq
                        .eq("state", 1)
                        .or()
                        .eq("state", 2)
                );
        List<OrderClass> order = orderClassMapper.selectList(wrapper);

        return getSimpleOrder(order);
    }

    /**
     * 查询该用户已支付的所有订单
     *
     * @param userId
     * @return
     */
    public List<OrderClassSimpleVO> listPayOrderByUserId(
            Long userId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        QueryWrapper<OrderClass> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
                .eq("is_delete", 0)
                .eq("state", 3);
        List<OrderClass> order = orderClassMapper.selectList(wrapper);

        return getSimpleOrder(order);
    }

    /**
     * 查询该用户待支付的所有订单
     *
     * @param userId
     * @return
     */
    public List<OrderClassSimpleVO> listNotPayOrderByUserId(
            Long userId, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        QueryWrapper<OrderClass> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", userId)
                .eq("is_delete", 0)
                .eq("state", 0);
        List<OrderClass> order = orderClassMapper.selectList(wrapper);

        List<OrderClassSimpleVO> list = getSimpleOrder(order);
        list.removeIf(simpleVO -> simpleVO.getState() != 0);
        return list;
    }

    /**
     * 电脑网页支付功能
     *
     * @param orderId
     * @param httpResponse
     */
    public void pay(Long orderId, String returnUrl, HttpServletResponse httpResponse) {
        System.out.println("orderId -> " + orderId);
        OrderClass orderClass = orderClassMapper.selectById(orderId);
        System.out.println("不为空");

        if (isOrderError(orderClass)) {
            // 判断课程是否有购买
            UserHaveBuy one = dubboUserHaveBuyService.getByUserIdClassesId(
                    orderClass.getUserId(), orderClass.getClassId());
            if (one != null) {
                throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                        "该课程已购买,请勿重复购买!");
            }

            System.out.println("进来了");
            Alipay alipay = new Alipay();
            BeanUtils.copyProperties(orderClass, alipay);
            System.out.println("开始查询");
            System.out.println("classId: " + orderClass.getClassId());
//            System.out.println("specificationId");
            CommodityOrderClassVO goods = dubboClassService
                    .getOrderClassById(orderClass.getClassId());
            System.out.println("title -> " + goods.getTitle());
            alipay.setTitle(goods.getTitle());
            alipay.setPrice(orderClass.getPrice());
            alipay.setSpecification(goods.getTypeName());

            alipay.setUrl(AliPayEnum.ORDER_CLASS.getType());
            alipay.setReturnUrl(returnUrl);
            System.out.println("-----------跳转页面 -> "+returnUrl);

            AliPayUtil.pay(alipay, httpResponse);
        }
    }

    /**
     * 手机端支付
     *
     * @param orderId
     * @param httpResponse
     */
    public void phonePay(Long orderId, HttpServletResponse httpResponse) {
        System.out.println("orderId -> " + orderId);
        OrderClass orderClass = orderClassMapper.selectById(orderId);
        if (isOrderError(orderClass)) {
            System.out.println("进来了");
            Alipay alipay = new Alipay();
            BeanUtils.copyProperties(orderClass, alipay);
            System.out.println("开始查询");
            System.out.println("goodsId: " + orderClass.getClassId());
            System.out.println("specificationId");
            CommodityOrderClassVO classById = dubboClassService
                    .getOrderClassById(orderClass.getClassId());
            System.out.println("title -> " + classById.getTitle());
            alipay.setTitle(classById.getTitle());
            alipay.setPrice(orderClass.getPrice());
            alipay.setSpecification(classById.getTypeName());

            alipay.setUrl(AliPayEnum.ORDER_CLASS.getType());

            AliPayUtil.phonePay(alipay, httpResponse);
        }
    }

    /**
     * 手机端app支付
     *
     * @param orderId
     * @param httpResponse
     */
    public void appPay(Long orderId, HttpServletResponse httpResponse) {
        System.out.println("orderId -> " + orderId);
        OrderClass orderClass = orderClassMapper.selectById(orderId);
        if (isOrderError(orderClass)) {
            System.out.println("进来了");
            Alipay alipay = new Alipay();
            BeanUtils.copyProperties(orderClass, alipay);
            System.out.println("开始查询");
            System.out.println("goodsId: " + orderClass.getClassId());
            System.out.println("specificationId");
            CommodityOrderClassVO classById = dubboClassService.
                    getOrderClassById(orderClass.getClassId());
            System.out.println("title -> " + classById.getTitle());
            alipay.setTitle(classById.getTitle());
            alipay.setPrice(orderClass.getPrice());
            alipay.setSpecification(classById.getTypeName());

            alipay.setUrl(AliPayEnum.ORDER_CLASS.getType());

            AliPayUtil.appPay(alipay, httpResponse);
        }
    }

    /**
     * 支付功能的同步调用
     *
     * @param orderId
     * @param request
     */
    public void returnUrl(Long orderId, HttpServletRequest request) {
        System.out.println("-----好戏开场了-----");
        String state = AliPayUtil.returnUrl(request);
        Map<String, String> payStateMap = AliPayUtil.getAlipayInformation(request);
        System.out.println("=================================同步回调结束=====================================");
        if ("ok".equals(state)) {
            OrderClass orderGoods = new OrderClass();
            orderGoods.setId(orderId);
            orderGoods.setAlipayNumber(payStateMap.get("trade_no"));
            orderGoods.setState(3);

            try {
                orderGoods.setPayTime(TimeUtil
                        .strToDate(payStateMap.get("notify_time"),
                                "yyyy-MM-dd HH:mm:ss"));
            } catch (ParseException e) {
                refund(orderId);
                throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                        "服务器忙,请稍后重试");
            }

            orderGoods.setUpdateTime(TimeUtil
                    .localDateTimeToDate(LocalDateTime.now()));
            orderClassMapper.updateById(orderGoods);
        } else {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "发生未知错误,支付失败");
        }

        OrderClass orderClass = orderClassMapper.selectById(orderId);
        UserHaveBuy userHaveBuy = new UserHaveBuy();
        userHaveBuy.setUserId(orderClass.getUserId());
        userHaveBuy.setCourseId(orderClass.getClassId());
//        userHaveBuy.setCreateTime(orderClass.getPayTime());
//        userHaveBuy.setUpdateTime(Time
//        Util.localDateTimeToDate(LocalDateTime.now()));
        System.out.println("=======插入创建时间=======");
        userHaveBuy.setCreateTime(TimeUtil.dateToLocalDateTime(orderClass.getPayTime()));
        System.out.println("=======插入创建时间成功=======");
        userHaveBuy.setUpdateTime(LocalDateTime.now());
        System.out.println("createTime: "+userHaveBuy.getCreateTime());
        System.out.println("updateTime: "+userHaveBuy.getUpdateTime());
        boolean result = dubboUserHaveBuyService.save(userHaveBuy);

        if (!result) {
            refund(orderId);
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "服务器忙,请稍后重试");
        }
    }

    /**
     * 退款
     *
     * @param orderId
     */
    public void refund(Long orderId) {
        OrderClass orderClass = orderClassMapper.selectById(orderId);

        String state = null;
        if (orderClass.getState() == 3) {
            Alipay alipay = new Alipay();
            BeanUtils.copyProperties(orderClass, alipay);
            CommodityOrderClassVO goods = dubboClassService.getOrderClassById(
                    orderClass.getClassId());
            alipay.setSpecification(goods.getTypeName());
            alipay.setTitle(goods.getTitle());
            alipay.setPrice(orderClass.getPrice());

            state = AliPayUtil.refund(alipay);
        } else {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "退款失败,该订单未付款");
        }

        if ("ok".equals(state)) {
            OrderClass updateOrder = new OrderClass();
            updateOrder.setId(orderId);
            updateOrder.setState(4);
            int rows = orderClassMapper.updateById(updateOrder);

            if (rows == 0) {
                throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                        "发生未知错误,退款失败,请联系工作人员");
            }
        } else {
            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                    "发生未知错误,退款失败,请联系工作人员");
        }

    }

    /**
     * 判断订单是否可用的方法
     *
     * @param orderClass
     * @return
     */
    private Boolean isOrderError(OrderClass orderClass) {
        if (orderClass == null || orderClass.getIsDelete() == 1) {
            throw new ToeServiceException(StateEnum.ERR_ORDER_EMPTY,
                    "订单不存在");
        }

        if (orderClass.getState() == 4) {
            throw new ToeServiceException(StateEnum.ERR_ORDER_EMPTY,
                    "订单已退款");
        }

        if (orderClass.getState() == 3) {
            throw new ToeServiceException(StateEnum.ERR_ORDER_EMPTY,
                    "订单已支付");
        }

        if (orderClass.getState() == 1) {
            throw new ToeServiceException(StateEnum.ERR_ORDER_CLOSE,
                    "您已取消订单");
        }

        if (orderClass.getState() == 0) {
            LocalDateTime endTime = TimeUtil
                    .dateToLocalDateTime(orderClass.getCreateTime())
                    .plusMinutes(15);
            LocalDateTime nowTime = LocalDateTime.now();
            if (nowTime.isAfter(endTime)) {
                Integer rows = updateIsEnable(orderClass.getId());
                if (rows == 0) {
                    throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                            "服务器忙,请稍后重试");
                }
                orderClass.setState(2);
            }
        }

        if (orderClass.getState() == 2) {
            throw new NoRollbackForToeServiceException(
                    StateEnum.ERR_SERVER_ERROR, "支付超时,订单已取消");
        }

        return true;
    }

    /**
     * 获取订单基本信息的方法
     *
     * @param order
     * @return
     */
    private List<OrderClassSimpleVO> getSimpleOrder(List<OrderClass> order) {
        System.out.println("===============开始解析===============");
//        order.forEach(System.out::println);
        List<OrderClassSimpleVO> list = new ArrayList<>();
//        System.out.println("order -> "+order);
        System.out.println("order.size() = " + order.size());
        if (order.size() == 0) return list;

        System.out.println("===============没有错1===============");
        List<Long> classIds = new ArrayList<>();
        for (OrderClass orderClass : order) {
            classIds.add(orderClass.getClassId());
        }
        System.out.println("===============没有错2===============");
        System.out.println(classIds.size());
        classIds.forEach(System.out::println);

        classIds = classIds.stream().distinct().collect(Collectors.toList());

        System.out.println("去重后: " + classIds.size());
        classIds.forEach(System.out::println);
        List<CommodityOrderClassVO> classesByIds =
                dubboClassService.listOrderClassesByIds(classIds);
        System.out.println("goods -> ");
        classesByIds.forEach(s -> System.out.println(s.getBusinessId()));

        List<Long> businessIds = new ArrayList<>();
        Map<Long, CommodityOrderClassVO> goodsMap = new HashMap<>();
        for (CommodityOrderClassVO clsses : classesByIds) {
            goodsMap.put(clsses.getId(), clsses);
            businessIds.add(clsses.getBusinessId());
        }
        businessIds = businessIds.stream().distinct()
                .collect(Collectors.toList());
        System.out.println("businessId: ");
        businessIds.forEach(System.out::println);
        List<BusinessInformation> business =
                dubboBusinessService.listByIds(businessIds);

        Map<Long, BusinessInformation> businessMap = new HashMap<>();
        for (BusinessInformation businessInformation : business) {
            businessMap.put(businessInformation.getId(), businessInformation);
        }

        goodsMap.entrySet().forEach(System.out::println);
        for (OrderClass orderClass : order) {
            OrderClassSimpleVO orderClassSimpleVO = new OrderClassSimpleVO();
            BeanUtils.copyProperties(orderClass, orderClassSimpleVO);

            Long goodsId = orderClass.getClassId();
            CommodityOrderClassVO classValue = goodsMap.get(goodsId);
            if (classValue != null) {
                orderClassSimpleVO.setClassTitle(classValue.getTitle());
                orderClassSimpleVO.setClassCover(classValue.getCover());
                orderClassSimpleVO.setClassType(classValue.getTypeName());

                orderClassSimpleVO.setPrice(classValue.getPresentPrice());
                orderClassSimpleVO.setTolPrice(orderClass.getPrice());

                Long businessId = classValue.getBusinessId();
                BusinessInformation businessValue = businessMap.get(businessId);
                orderClassSimpleVO.setBusinessId(businessId);
                orderClassSimpleVO.setBusinessName(businessValue.getName());

                // 查询订单剩余支付时间
                if (orderClass.getState() == 0
                        && orderClass.getIsDelete() == 0) {
                    String time = TimeUtil.getRemainingPayTime(orderClass.getCreateTime());
                    if (time == null) {
                        Integer rows = updateIsEnable(orderClass.getId());
                        if (rows == 0) {
                            throw new ToeServiceException(StateEnum.ERR_SERVER_ERROR,
                                    "服务器忙,请稍后重试");
                        }
                        orderClassSimpleVO.setState(2);
                    } else {
                        orderClassSimpleVO.setRemainingPayTime(time);
                    }
                }
            }
            list.add(orderClassSimpleVO);
        }

        return list;
    }

    /**
     * 系统取消订单的方法
     *
     * @param orderId
     * @return
     */
    private Integer updateIsEnable(Long orderId) {
        OrderClass order = new OrderClass();
        order.setId(orderId);
        order.setState(2);
        return orderClassMapper.updateById(order);
    }

}
